<?php
namespace app\controller;

use app\exception\ApiException;
use app\extensions\lib\FcmAccessToken;
use app\extensions\lib\Output;
use app\extensions\lib\push\BasePush;
use app\extensions\lib\push\HmsPush;
use app\extensions\lib\ta_shushu\Shushu;
use app\model\TokenInfo;
use app\queue\redis\in_page\InPush;
use app\queue\redis\push\Push;
use app\queue\redis\push_page\PagePush;
use app\queue\redis\shushu\DeviceEvent;
use app\queue\redis\shushu\RequestEvent;
use Firebase\JWT\JWT;
use Kreait\Firebase\Factory;
use Kreait\Firebase\Messaging\AndroidConfig;
use Kreait\Firebase\Messaging\CloudMessage;
use Kreait\Firebase\Messaging\Notification;
use support\Db;
use support\Log;
use support\Request;
use Webman\RedisQueue\Redis;
use Workerman\Connection\AsyncTcpConnection;

class Pushes
{
    const FILE_URL_EXTENSION = ['csv','txt'];
    private $packageList = [];

    public function reCall(Request $request){
        $request_id = $request->input('request_id','');
        $datasKey = \app\extensions\lib\push\Push::getRequestData($request_id);
        $status = Redis::hSet($datasKey,'recall',1);
        Redis::expire($datasKey,86400);
        return Output::success(compact('status'));
    }

    public function finishRequestPush(Request $request){
        $request_id = $request->input('id','');
        $cate_id = $request->input('cate_id','');
        $channel = $request->input('channel','');
        $datasKey = \app\extensions\lib\push\Push::getRequestData($request_id);
        $callback_url = Redis::hGet($datasKey,'callback_url');
        //标识有没有完成
        $status = false;
        if($callback_url){
            $status = \app\extensions\lib\push\Push::finishRequestPush($request_id,$cate_id,$channel);
        }

        return Output::success(compact('status'));
    }
    public function messageClick(Request $request){
        return $this->messageStatus($request,true);
    }

    public function messageStatus(Request $request,$is_click=false){
        $post = $request->post();
        $message_id = $post['message_id'] ?? '';
        $udid = $post['udid'] ?? '';
        $os_id = $post['os_id'] ?? '';
        Log::channel('request')->info('messageStatus:'.json_encode($post));
        if(empty($message_id) || !$udid){
            //旧版没有数据
            $status = 0;
            $msg = 'message_id or udid is null';
            return Output::success(compact('status','msg'));
            throw new ApiException($msg);
        }
        //华为是分配处理的，消息体的message_id 是一样的
        if($os_id==3){
            $message_id = HmsPush::getEventId($udid,$message_id);
        }
        $DeviceEvent = new DeviceEvent();
        $properties = ['udid'=>$udid];
        if($is_click){
            $properties['click_status'] = '1';
            $properties['click_time'] = date("Y-m-d H:i:s",time());
        }else{
            $properties['send_status'] = '1';
            $properties['send_time'] = date("Y-m-d H:i:s",time());
        }
        $status =\Webman\RedisQueue\Redis::send($DeviceEvent->queue,[
            'package_id' => $package_id ?? 0,
            'udid' => $udid,
            'params' => [
                'track_update',
                '',
                $udid,
                $properties,
                BasePush::EVENT_DEVICE_PUSH_LOG,
                $message_id,
                false
            ],
        ]);
        Log::channel('request')->info('sdk:is_click:'.$is_click.':status:'.$status.':'.json_encode(
            $properties+compact('udid','udid','message_id','os_id')));
        return Output::success(compact('status'));
    }

    private function getPackageList($id,$flush=false){
        if($flush || empty($this->packageList)){
            $packageList = DB::connection('mysql_admin')->table('packages')
                ->select()->get()->toArray();
            $this->packageList = array_column(object2array($packageList),null,'id');
            //var_dump('new PackageList');
        }else{

        }
        //dump($this->packageList);
        return $this->packageList[$id] ?? [];
    }

    private function checkParams($data){
        $package_id = $data['package_id'] ?? 0;
        $game_id = $data['game_id'] ?? 0;
        //$packageInfo = $this->getPackageList($package_id);
        if(!$package_id && !$game_id){
            throw new ApiException('game_id or package_id is null');
        }
    }


    protected function setUidAndBlack($data,$request_id){
        $opts = [
            'http' => [
                'method' => 'GET','timeout' => 58,
            ]
        ];
        $udids = [];
        $uid_url = '';
        $context = stream_context_create($opts);
        if(isset($data['udid'])){
            $udids = $data['udid'];
            !is_array($udids) && $udids = explode(',',$udids);
        }else{
            $uid_url = $data['udid_list_url'] ?? '';

            if($uid_url){
                list($exists,$size,$extension) = checkUrlInfo($uid_url);
                if(!in_array(strtolower($extension),self::FILE_URL_EXTENSION)){
                    throw new ApiException('udid_list_url文件不支持的格式');
                }
                if(!$exists){
                    throw new ApiException('udid_list_url文件不存在');
                }
                if($size){
                    //限制 100M
                    if($size/ 1024/ 1024 > 100){
                        throw new ApiException('udid_list_url文件大小大于100M');
                    }
                }

            }


        }

        //黑名单设置
        $burl = $data['budid_list_url'] ?? '';
        $budid = $data['budid'] ?? '';
        $bkey = \app\extensions\lib\push\Push::getBlackList($request_id);
        //黑名单记录
        if($budid){
            !is_array($budid) && $budid = array_filter(explode(',',$budid));
            if(count($budid)>100){
                throw new ApiException('budid参数长度不能大于100');
            }
            foreach ($budid as $bu){
                Redis::lPush($bkey,$bu);//数据先放到指定缓存队列中,getUserList查询in时间久
            }
        }
        //黑名单url地址获取并记录
        if($burl){
            list($exists,$size,$extension) = checkUrlInfo($burl);
            if(!in_array(strtolower($extension),self::FILE_URL_EXTENSION)){
                throw new ApiException('budid_list_url文件不支持的格式');
            }
            if($size){
                //限制 10M
                if($size/ 1024/ 1024 > 10){
                    throw new ApiException('budid_list_url文件大小大于10M');
                }
            }
            if($exists){
                foreach (array_filter(explode("\n",trim(str_replace("\r",'',file_get_contents($burl, false, $context))))) as $bu){
                    Redis::lPush($bkey,$bu);//数据先放到指定缓存队列中,getUserList查询in时间久
                }
            }else{
                throw new ApiException('budid_list_url文件不存在');
            }
            Redis::expire($bkey,86400);//单次请求黑名单的时间
        }

        return [$udids,$uid_url];
    }


    public function pushSdk(Request $request){
        //return Output::success($request->all());
        $cate_id = $request->input('cate_id');
        if(!$cate_id){
            throw new ApiException('cate_id is null');
        }

        $return = null;
        try{
            $return =  $this->batch_push($request,\app\extensions\lib\push\Push::TAPPLUS_ADMIN_CHANNEL);
        }catch (ApiException $apiException){
            throw $apiException;
        }


        //记录请求成功的请求记录
        if(class_basename($return)=='Response'){
            /* @var $return \support\Response */
            $data = $return->rawBody();
            $data = json_decode($data,true)?:[];
            $RequestEvent = new RequestEvent();
            if(isset($data['code']) && $data['code']==CODE_SUCCESS && isset($data['data']['request_id'])){
                $request_id = $data['data']['request_id'];
                $properties = compact('request_id');
                $properties['request_time'] = date('Y-m-d H:i:s');
                $properties['params'] = array_merge($request->all(),['max_id'=>$data['data']['max_id'] ?? 0]);
                $properties['#ip']= ipHandle($request->getRealIp());
                \Webman\RedisQueue\Redis::send($RequestEvent->queue,array_merge([],
                    compact('cate_id','request_id','properties')));
            }
        }
        return $return;
    }

    public function push(Request $request){
        $data = $request->post();
        $this->checkParams($data);

        $TokenInfo = new TokenInfo();
        $userList = $TokenInfo->getUserList($data);

        $PublicPush = new \app\extensions\lib\push\Push();

        $result = $PublicPush->push($userList,$data);
        $request_id = $result['request_id'] ?? '';
        Log::channel('request')->info($request_id.':'.json_encode($data));
        return Output::success($result);
    }
    public function batch_push(Request $request,$channel=''){
        $data = $request->post();
        unset($data['channel']);
        $data['channel'] = $channel;
        $is_async=true;
        $request_id = $data['request_id'] ?? requestId();
        if(in_array($channel,\app\extensions\lib\push\Push::PUSH_INNER)){

        }else{
            $this->checkBatchParams($data);
        }

        Log::channel('request')->info($request_id.':'.json_encode($data));

        //设置日志透传的信息
        $payload = $request->input('payload');
        !is_array($payload) && $payload = json_decode($payload,true) ?: [];
        $payloadKey = \app\extensions\lib\push\Push::getPayloadKey($request_id);
        Redis::set($payloadKey,json_encode($payload));
        Redis::expire($payloadKey,86400);//的时间


        //回调信息
        $callback_url = $request->input('callback_url');
        $datasKey = \app\extensions\lib\push\Push::getRequestData($request_id);
        Redis::hSet($datasKey,'callback_url',$callback_url);
        Redis::expire($datasKey,86400);


        //udid 优先于 uid_url
        list($udid,$uid_url) = $this->setUidAndBlack($data,$request_id);//设置和获取udid信息（指定udid和黑名单udid）
        //检测批量的udid
        if(count($udid)>100){
            throw new ApiException('udid参数长度不能大于100');
        }

        $TokenInfo = new TokenInfo();
        $max = $TokenInfo->max('id');
        $InPush = new InPush();
        $datas = $TokenInfo->getBatchUserList($data);
        //检测批量的udid
        foreach ($datas['userData'] as $key =>$userData){
            if(isset($userData['udid'])){
                $one_udid = $userData['udid'];
                !is_array($one_udid) && $one_udid = explode(',',$one_udid);
                $udids = array_filter($one_udid);
                if(count($udids)>100){
                    throw new ApiException('udid参数长度不能大于100');
                }
            }

        }
        if($uid_url && count($datas['userData'])>1){
            throw new ApiException('push_payloads 和 文件方式不能同时或...');
        }
        $PublicPush = new \app\extensions\lib\push\Push();
        $default = [];
        $return = ['request_id'=>$request_id,'is_async'=>$is_async];
        if($channel==$PublicPush::TAPPLUS_ADMIN_CHANNEL){
            $return['max_id'] = $max;
        }
        foreach ($datas['userData'] as $key =>$userData){
            $message = $datas['message'][$key];
            $info = "batch:{$key}:times:".count($datas['userData']);
            // in类型发送
            if($uid_url){
                $field = 'udid';
                unset($userData['udid']);//清除udid条件
                $dkey = $request_id.':'.InPush::$update_redis_queue_key.'_sdk';//存储key
                \Webman\RedisQueue\Redis::send($InPush->queue,array_merge(['key'=>$dkey,'url'=>$uid_url],
                    compact('field','userData','message','request_id','info')));//触发队列（添加队列数据
                continue;
            }

            //只发送第一页，其他，异步发送
            /*$page = 1;
            $userList = $TokenInfo->getUserList($userData,$page);
            $pageInfo = 'pagePush:'.$page;
            $page++;
            $results = $PublicPush->push($userList,$message,$is_async,$request_id,[],$pageInfo);*/
            $userData['max_id'] = $max;//最大id限制
            $page = 1;
            $datas = compact('request_id','userData','message','page','info');


            $status = Redis::send(PagePush::$update_redis_queue_key,$datas,1);
            $return['status'] = $status;
            try{

            }catch (\Throwable $e){
                Log::warning('push result merge error::'.$e->getMessage());
            }



        }


        //$result = $PublicPush->push($userList,$data);

        return Output::success($return);
    }


    public function insidePush(Request $request){
        $data = $request->post();

        $TokenInfo = new TokenInfo();
        $userList = $TokenInfo->getInsideUserList($data);

        $PublicPush = new \app\extensions\lib\push\Push();

        $result = $PublicPush->push($userList,$data);

        return Output::success($result);
    }

    private function checkBatchParams($data)
    {
        $game_id = $data['game_id'] ?? '';
        $version = $data['version'] ?? '';
        //$packageInfo = $this->getPackageList($package_id);
        if(!$game_id){
            throw new ApiException('game_id is null');
        }
        if(!$version){
            throw new ApiException('version is null');
        }
        $push_data_public = $data['push_data_public'] ?? '';
        is_string($push_data_public) && $push_data_public = json_decode($push_data_public,true) ?: [];
        $push_payloads = $data['push_payloads'] ?? '';
        is_string($push_payloads) &&$push_payloads = json_decode($push_payloads,true) ?: [];
        if(!$push_data_public && !$push_payloads){
            throw new ApiException('push message is null');
        }

    }


}
